package cos.android.tim.utils;

import java.io.IOException;
import java.util.Properties;
import java.util.Vector;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import cos.android.tim.R;
import cos.android.tim.element.Element;
import cos.android.tim.element.Moveable;
import cos.android.tim.objects.Ball;
import cos.android.tim.objects.Balloon;
import cos.android.tim.objects.Batery;
import cos.android.tim.objects.Bucket;
import cos.android.tim.objects.Bulb;
import cos.android.tim.objects.Chain;
import cos.android.tim.objects.Elements;
import cos.android.tim.objects.Hook;
import cos.android.tim.objects.JumpBox;
import cos.android.tim.objects.Punch;
import cos.android.tim.objects.Radio;
import cos.android.tim.objects.Rampa;
import cos.android.tim.objects.Rope;
import cos.android.tim.objects.Trampoline;
import cos.android.tim.objects.Wall;

public class Level implements Cloneable {

	private Vector<Element> elements;
	private Vector<Factory> factories;

	private Vector<Element> elementsInits;

	private float gravity = 0;
	private Element keyElement;
	Properties properties;

	public Level(Resources res, Properties properties, int level, int world) {

		// Este metodo se utilizara para cargar el nivel por archivo.
		gravity = Float.parseFloat((String) properties.get("gravity"));
		this.properties = properties;
		factories = new Vector<Factory>();
		elements = new Vector<Element>();

		Factory factory;

		XmlResourceParser parser = null;

		parser = res.getXml(R.xml.level1_1);

		try {
			parser.next();
			int eventType = parser.getEventType();
			while (eventType != XmlPullParser.END_DOCUMENT) {
				if (eventType == XmlPullParser.START_TAG
						&& parser.getName().equals("level")
						&& parser.getAttributeIntValue(0, -1) == world
						&& parser.getAttributeIntValue(1, -1) == level) {
					while (!(eventType == XmlPullParser.END_TAG && parser
							.getName().equals("level"))) {
						if (eventType == XmlPullParser.START_TAG) {
							if (parser.getName().equals("Goal")) {
								if (parser.getAttributeValue(0).equals(
										"activateElement")) {
									keyElement = lookElementByName(parser
											.getAttributeValue(1));
								}
							}

							if ((parser.getName().equals("Element"))
									|| (parser.getName().equals("Factory"))) {
								Element element = null;

								switch (Elements.valueOf(parser
										.getAttributeValue(0))) {
								case HorizontalWall:
									element = new Wall(
											BitmapFactory.decodeResource(res,
													R.drawable.horizontalwall),
											BitmapFactory
													.decodeResource(
															res,
															R.drawable.horizontalwallfiltrado),
											BitmapFactory
													.decodeResource(
															res,
															R.drawable.horizontalwallmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"HorizontalWall");

									break;
								case VerticalWall:
									element = new Wall(
											BitmapFactory.decodeResource(res,
													R.drawable.verticalwall),
											BitmapFactory
													.decodeResource(
															res,
															R.drawable.verticalwallfiltrado),
											BitmapFactory
													.decodeResource(
															res,
															R.drawable.verticalwallmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"VerticalWall");
									break;
								case TenisBall:
									element = new Ball(
											BitmapFactory.decodeResource(res,
													R.drawable.tennisball),
											BitmapFactory.decodeResource(res,
													R.drawable.tennisball),
											BitmapFactory.decodeResource(res,
													R.drawable.tennisballmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),

											Float.parseFloat((String) properties
													.get("tenisBallFlexibility")),
											Float.parseFloat((String) properties
													.get("tenisBallWeight")),
											"TenisBall");
									break;
								case JumpBox:
									element = new JumpBox(
											BitmapFactory.decodeResource(res,
													R.drawable.fan),
											BitmapFactory.decodeResource(res,
													R.drawable.fan),
											BitmapFactory.decodeResource(res,
													R.drawable.fanmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"JumpBox");
									break;
								case Punch:
									element = new Punch(
											BitmapFactory.decodeResource(res,
													R.drawable.punch),
											BitmapFactory.decodeResource(res,
													R.drawable.punch),
											BitmapFactory.decodeResource(res,
													R.drawable.punchmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Punch");
									break;
								case Radio:
									element = new Radio(
											BitmapFactory.decodeResource(res,
													R.drawable.radio),
											BitmapFactory.decodeResource(res,
													R.drawable.radio),
											BitmapFactory.decodeResource(res,
													R.drawable.radio),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Radio");
									break;
								case Batery:
									element = new Batery(
											BitmapFactory.decodeResource(res,
													R.drawable.batery),
											BitmapFactory.decodeResource(res,
													R.drawable.batery),
											BitmapFactory.decodeResource(res,
													R.drawable.baterymini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Batery");
									break;
								case Rampa:
									element = new Rampa(
											BitmapFactory.decodeResource(res,
													R.drawable.rampa),
											BitmapFactory.decodeResource(res,
													R.drawable.rampa),
											BitmapFactory.decodeResource(res,
													R.drawable.rampamini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											0.75f, "Rampa", 0);
									break;
								case Rampa2:
									element = new Rampa(
											BitmapFactory.decodeResource(res,
													R.drawable.rampa2),
											BitmapFactory.decodeResource(res,
													R.drawable.rampa2),
											BitmapFactory.decodeResource(res,
													R.drawable.rampamini2),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											0.75f, "Rampa", 1);
									break;
								case Chain:
									element = new Chain(
											BitmapFactory.decodeResource(res,
													R.drawable.chain),
											BitmapFactory.decodeResource(res,
													R.drawable.chain),
											BitmapFactory.decodeResource(res,
													R.drawable.chain),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Chain");
									break;
								case BowlingBall:
									element = new Ball(
											BitmapFactory.decodeResource(res,
													R.drawable.bowlingball),
											BitmapFactory.decodeResource(res,
													R.drawable.bowlingball),
											BitmapFactory.decodeResource(res,
													R.drawable.bowlingballmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),

											Float.parseFloat((String) properties
													.get("bowlingBallFlexibility")),
											Float.parseFloat((String) properties
													.get("bowlingBallWeight")),
											"BowlingBall");
									break;
								case Bucket:
									element = new Bucket(
											BitmapFactory.decodeResource(res,
													R.drawable.bucket),
											BitmapFactory.decodeResource(res,
													R.drawable.bucket),
											BitmapFactory.decodeResource(res,
													R.drawable.bucket),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),

											Float.parseFloat((String) properties
													.get("bucketFlexibility")),
											Float.parseFloat((String) properties
													.get("bucketWeight")),
											"Bucket");

									break;
								case Hook:
									element = new Hook(
											BitmapFactory.decodeResource(res,
													R.drawable.hook),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Hook");
									break;
								case Tackle:
									element = new Hook(
											BitmapFactory.decodeResource(res,
													R.drawable.tackle),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Tackle");

									break;

								case Trampoline:
									element = new Trampoline(
											BitmapFactory.decodeResource(res,
													R.drawable.trampoline),
											BitmapFactory.decodeResource(res,
													R.drawable.trampoline),
											BitmapFactory.decodeResource(res,
													R.drawable.trampolinemini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Trampoline");

									break;

								case Bulb:
									element = new Bulb(
											BitmapFactory.decodeResource(res,
													R.drawable.bulb),
											BitmapFactory.decodeResource(res,
													R.drawable.bulb),
											BitmapFactory.decodeResource(res,
													R.drawable.bulb),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Bulb");

									break;

								case Balloon:
									element = new Balloon(
											BitmapFactory.decodeResource(res,
													R.drawable.balloon),
											BitmapFactory.decodeResource(res,
													R.drawable.balloon),
											BitmapFactory.decodeResource(res,
													R.drawable.balloonmini),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),

											Float.parseFloat((String) properties
													.get("balloonFlexibility")),
											Float.parseFloat((String) properties
													.get("balloonWeight")),
											"Balloon");
									break;

								case Rope:
									element = new Rope(
											BitmapFactory.decodeResource(res,
													R.drawable.chain),
											parser.getAttributeIntValue(2, 0),
											parser.getAttributeIntValue(3, 0),
											"Rope");
									break;
								}

								if (parser.getName().equals("Factory")) {
									element.setMoveable(new Moveable());
									factory = new Factory();
									factory.setElement(element);
									element.setFather(factory);
									factory.setNumber(parser
											.getAttributeIntValue(1, 0));
									factories.add(factory);

								} else {
									element.setMoveable(null);
									element.setName(parser.getAttributeValue(1));
									elements.add(element);
								}
							}
						}
						eventType = parser.next();
					}
				}
				eventType = parser.next();
			}
			elementsInits = new Vector<Element>(elements);

		} catch (XmlPullParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/*
	 * public void basicInizialize(Resources res, Properties properties) {
	 * 
	 * factories = new Vector<Factory>(); elements = new Vector<Element>();
	 * 
	 * Factory horizontalWalls = new Factory(new Wall(
	 * BitmapFactory.decodeResource(res, R.drawable.horizontalwall), 0, 0, 30,
	 * 90), 7); Factory verticalWalls = new Factory(new Wall(
	 * BitmapFactory.decodeResource(res, R.drawable.verticalwall), 0, 0, 90,
	 * 30), 7); Factory tenisBalls = new Factory(new
	 * Ball(BitmapFactory.decodeResource( res, R.drawable.tennisball), 0, 0, 20,
	 * Float.parseFloat((String) properties .get("tenisBallFlexibility")),
	 * Float.parseFloat((String) properties.get("tenisBallWeight"))), 7);
	 * 
	 * Factory chains = new Factory(new Chain(BitmapFactory.decodeResource( res,
	 * R.drawable.chain), 0, 0, 32, 50), 7);
	 * 
	 * Factory bateries = new Factory(new Batery(BitmapFactory.decodeResource(
	 * res, R.drawable.batery), 0, 0, 31, 45), 7);
	 * 
	 * Factory rampas = new Factory(new Rampa(BitmapFactory.decodeResource( res,
	 * R.drawable.rampa), 0, 0, 60, 90, 0.75f), 7);
	 * 
	 * Factory radios = new Factory(new Radio(BitmapFactory.decodeResource( res,
	 * R.drawable.radio), 0, 0, 52, 80), 7);
	 * 
	 * factories.add(horizontalWalls); factories.add(verticalWalls);
	 * factories.add(tenisBalls); factories.add(rampas); factories.add(chains);
	 * factories.add(bateries); factories.add(radios);
	 * 
	 * gravity = Float.parseFloat((String) properties.get("gravity"));
	 * 
	 * }
	 */

	public Factory getFactoryTouched(float touchX, float touchY) {

		for (int i = 0; i < factories.size(); i++) {
			Factory factory = factories.elementAt(i);
			if (factory.isTouched(touchX, touchY)) {
				return factory;
			}
		}
		return null;
	}

	public Element getElementTouched(float touchX, float touchY) {
		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);

			if (element.isTouched(touchX, touchY)) {
				return element;
			}

		}
		return null;
	}

	public void updateGame(float elapsed, Canvas canvas) {

		updateGravity(elapsed);
		checkCollides();
		checkInteractions(elapsed);

		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			if ((element.isDinamicElement())) {
				if (element.getxPos() > canvas.getWidth()
						|| element.getyPos() > canvas.getHeight()) {
					element.setDinamicElement(null);
				}

				element.update(elapsed);
			}
		}
	}

	public void addElements(Element element) {

		elements.add(element);
	}

	public boolean checkGoal() {

		if (keyElement != null) {
			return keyElement.isActive();
		}
		return false;
	}

	private void updateGravity(float elapsed) {

		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			if (element.isDinamicElement()) {
				if (Math.abs(element.getoY()) < gravity * elapsed) {
					element.setLastHitted(null);
				}
				if (element instanceof Balloon) {
					element.applySpeed(
							0,
							Integer.parseInt((String) properties
									.get("balloonGravity")) * elapsed);
				} else {
					element.applySpeed(0, gravity * elapsed);
				}
			}
		}
	}

	private void checkCollides() {

		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			for (int j = i + 1; j < elements.size(); j++) {
				Element element2 = elements.elementAt(j);
				if (!(element.getLastHitted() == element2 || element2
						.getLastHitted() == element)) {
					Motor.colision(element, element2);

				}
			}
		}
	}

	public boolean isLevelCorrect() {

		boolean correct = true;
		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			if (!element.isCorrectPosition()) {
				correct = false;
			}
		}
		return correct;

	}

	public void checkCorrect() {

		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			boolean correct = true;

			for (int j = 0; j < elements.size(); j++) {
				Element element2 = elements.elementAt(j);
				if (element != element2) {
					if (Motor.correct(element, element2)) {
						if (element2.isMoveable()) {
							element2.setCorrectPosition(false);
						}
						correct = false;
					}
				}
			}
			if (element.isMoveable()) {
				element.setCorrectPosition(correct);
			}

		}
	}

	private void checkInteractions(float elapsed) {

		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.elementAt(i);
			if (element.isOn()) {
				for (int j = 0; j < elements.size(); j++) {
					Element element2 = elements.elementAt(j);

					if (element.getKind().equals("JumpBox")) {
						if ((element != element2)
								&& (element2.isDinamicElement())) {

							if ((element2.getCenterX() < element.getCenterX()
									+ element.getWidth() / 2)
									&& (element2.getCenterX() > element
											.getCenterX()
											- element.getWidth()
											/ 2)) {

								element2.applySpeed(0, (float) -(Integer
										.parseInt((String) properties
												.get("fanSpeed")) / Math.pow(
										(Motor.pointPointDistance(
												element.getCenterX(),
												element2.getCenterX(),
												element.getCenterY(),
												element2.getCenterY())), 2)));
							}

						}
					}
					if (element.getKind().equals("Punch")) {
						if ((element != element2)
								&& (element2.isDinamicElement())
								&& (element.getxPos() < element2.getxPos())) {
							if (Motor.pointPointDistance(element.getCenterX(),
									element2.getCenterX(), 0, 0) < 50) {
								if ((element2.getCenterY() < element
										.getCenterY() + element.getHeight() / 2)
										&& (element2.getCenterY() > element
												.getCenterY()
												- element.getHeight() / 2)) {
									element2.applySpeed(Float
											.parseFloat((String) properties
													.get("punchStrength")), 0);
								}
							}
						}
					}

					if (element.isElectricGenerator() && element.isActive()) {
						if (element2.isElectric()) {
							if (Interactions.interaction(element, element2)) {
								element2.action();
							}
						}
					}
				}
				if (element.getKind().equals("Punch")) {
					element.setOn(false);
				}
			}

		}

		/*
		 * for (int i = 0; i < elements.size(); i++) { Element element =
		 * elements.elementAt(i); if (element instanceof Rope) { Rope rope =
		 * (Rope) element; if (rope.isTied()) { if
		 * (rope.getElement1().isDinamicElement()) { Element el =
		 * rope.getElement1();
		 * 
		 * System.out.println("Previas: " + el.getoX() + " " + el.getoY());
		 * 
		 * float dxb = rope.getElement1().extremePoint().getxPos() -
		 * rope.getElement2().extremePoint().getxPos(); float dyb =
		 * rope.getElement1().extremePoint().getyPos() -
		 * rope.getElement2().extremePoint().getyPos();
		 * 
		 * float propX = (Math.abs(dyb) / (Math.abs(dxb) + Math .abs(dyb)));
		 * float propY = 1 - propX;
		 * 
		 * el.applySpeed( propX * Math.signum(-dxb) * el.getSpeed(), propY *
		 * el.getSpeed() * Math.signum(dyb)); System.out.println("Speed Post: "
		 * + el.getoX() + " " + el.getoY() + " " + propY + " " +
		 * Math.signum(-dyb) + " "); } } } }
		 */

	}

	private Element lookElementByName(String name) {

		for (Element element : elements) {
			if (element.isName(name)) {
				return element;
			}
		}
		return null;
	}

	public Vector<Element> getElements() {
		return elements;
	}

	public void setFactories(Vector<Factory> factories) {
		this.factories = factories;
	}

	public Vector<Factory> getFactories() {
		return factories;
	}

	public void deleteElement(Element element) {
		elements.remove(element);
	}

	public void resetLevel() {

		for (Element element : elements) {
			element.dispose();
		}
		elements = new Vector<Element>(elementsInits);
		// factories = new Vector<Factory>(factoriesInits);
		gravity = 0;
	}

	public void resetCharacteristics() {

		for (Element element : elements) {

			if (element.isElectric()) {
				element.setOn(true);
				element.setActive(false);
			}
			if (element.isDinamicElement()) {
				element.reset();
			}
		}
	}

	public StringBuffer saveLevel(String name) {
		System.out.println("Ir, vamos bien");
		try {

			StringBuffer ps = new StringBuffer("");

			ps.append("<?xml version='1.0' encoding='utf-8'?>");
			ps.append("<resources>");
			ps.append("<level>");
			ps.append("<factories>");

			for (Factory factory : factories) {
				ps.append("<Factory kind=\"" + factory.getElement().getKind()
						+ "\" numElements=\"" + factory.getNumber() + "\"/>");
			}
			ps.append("</factories>");
			ps.append("<initElements>");
			for (Element element : elements) {
				ps.append("<Element kind=\"" + element.getKind() + "\" name=\""
						+ element.getName() + "\" xpos=\""
						+ Math.round(element.getxPos()) + "\" ypos=\""
						+ Math.round(element.getyPos()) + "\"/>");
			}
			ps.append("</initElements>");
			ps.append("<Goal kind=\"activateElement\" keyElement=\"rad1\" />");
			ps.append("</level>");
			ps.append("</resources>");
			System.out.println("Escritura: " + ps);
			return ps;

		} catch (Exception e) {
			System.out.println(e.getMessage() + "DESASTREEEEEE");
			return null;
		}

	}

	@Override
	public Object clone() {

		Level clone;
		try {
			clone = (Level) super.clone();
			clone.elements = new Vector<Element>();
			clone.factories = new Vector<Factory>();
			for (int i = 0; i < elements.size(); i++) {
				Element array_element = elements.elementAt(i).clone();
				clone.elements.add(array_element);
			}
			for (int i = 0; i < factories.size(); i++) {
				Factory array_element = factories.elementAt(i).clone();
				clone.factories.add(array_element);
			}

			return clone;

		} catch (CloneNotSupportedException e) {
			System.out.println("Cloning not allowed.");
			return this;
		}
	}

	public void refactorElelemts() {

		for (int i = 0; i < elements.size(); i++) {

			Element element1 = elements.elementAt(i);
			for (int j = i + 1; j < elements.size(); j++) {
				Element element2 = elements.elementAt(j);

				if (element1.getKind() == "HorizontalWall"
						&& element2.getKind() == "HorizontalWall") {

					if (element1.getyPos() == element2.getyPos()) {
						if (element1.getxPos() < element2.getxPos()) {

							j--;
							element1.setWidth(element1.getWidth()
									+ element2.getWidth());

							System.out.println("width element: "
									+ element1.getWidth());
							element1.setSprite(Bitmap.createScaledBitmap(
									element1.getSprite(), element1.getWidth(),
									element1.getHeight(), false));
							element1.refreshAristas();
							elements.remove(element2);

						} else {
							j--;
							element2.setWidth(element2.getWidth()
									+ element1.getWidth());
							System.out.println("width element: "
									+ element2.getWidth());

							element2.setSprite(Bitmap.createScaledBitmap(
									element2.getSprite(), element2.getWidth(),
									element2.getHeight(), false));
							element2.refreshAristas();
							elements.remove(element1);
						}
					}
				}

			}
		}
	}

	public void resizeElements(double propX, double propY) {
		System.out.println("propX: " + propX + " y: " + propY);
		for (Element element : elements) {
			element.setxPos((int) (element.getxPos() * propX));
			element.setyPos((int) (element.getyPos() * propY));
			element.setWidth((int) (element.getWidth() * propX));
			element.setHeight((int) (element.getHeight() * propY));
			System.out.println("name: " + element.getKind() + "resize: "
					+ element.getWidth() + " " + element.getHeight());
			element.setSprite(Bitmap.createScaledBitmap(element.getSprite(),
					element.getWidth(), element.getHeight(), false));
			element.refreshAristas();
			// element.setRect(new Rect(0, 0, element.getWidth(),
			// element.getHeight()));
		}
		for (Factory factory : factories) {
			Element element = factory.getElement();
			element.setWidth((int) (element.getWidth() * propX));
			element.setHeight((int) (element.getHeight() * propY));
			element.setSprite(Bitmap.createScaledBitmap(element.getSprite(),
					element.getWidth(), element.getHeight(), false));
			element.refreshAristas();
			// element.setRect(new Rect(0, 0, element.getWidth(),
			// element.getHeight()));

		}
	}

}
